package com.zhn;

/**
 * 请你设计并实现一个满足  LRU (最近最少使用) 缓存 约束的数据结构。
 * 实现 LRUCache 类：
 * LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存
 * int get(int key) 如果关键字 key 存在于缓存中，则返回关键字的值，否则返回 -1 。
 * void put(int key, int value) 如果关键字 key 已经存在，则变更其数据值 value ；如果不存在，则向缓存中插入该组 key-value 。如果插入操作导致关键字数量超过 capacity ，则应该 逐出 最久未使用的关键字。
 * 函数 get 和 put 必须以 O(1) 的平均时间复杂度运行。
 *
 *
 */


import java.util.HashMap;
import java.util.Map;

/**
 * 1. 使用数组实现，无法实现O(1)
 * 2. 使用单向链表实现，但无法解决get后，无法达到O(1)
 * 3. 想要让get达到O(1)，加上哈希表
 * 4. 想让断开的链表连接起来时间复杂度达到O(1)，使用双向链表
 * 5. 最终: HashMap + LinkedList
 * JDK 提供 LinkedHashMap
 */
public class LRUCache {
    //定义容量
    int capacity;
    //定义当前存放数据长度
    int size;
    //定义头节点
    LinkedDouble head;
    //HashMap保证get时间复杂度O(1)
    Map<Integer,LinkedDouble> map = new HashMap<>();


    public LRUCache(int capacity) {
        this.capacity = capacity;
        head = new LinkedDouble();
        head.next = head;
        head.pre = head;
    }

    public int get(int key) {
        LinkedDouble node = map.get(key);
        if(node == null) return - 1;
        node = node.remove();
        head.insert(node);
        return node.val;
    }

    public void put(int key, int value) {
        LinkedDouble node = map.get(key);
        if(node == null){
            node = new LinkedDouble(key,value);
            map.put(key, node);
            size++;
        }else {
            node = node.remove();
            node.val = value;
        }
        head.insert(node);
        if(size > capacity){
            //删除头节点，最近最少使用节点
            LinkedDouble removed =  head.pre.remove();
            map.remove(removed.key);
            size--;
        }
    }

    public static void main(String[] args) {
        LRUCache lruCache = new LRUCache(2);
        lruCache.put(1,1);
        lruCache.put(2,2);
        int a = lruCache.get(1);
        lruCache.put(3, 3);
        lruCache.get(2);
        lruCache.put(4, 4);
        int b = lruCache.get(1);
        int c = lruCache.get(3);
        int d = lruCache.get(4);
        System.out.println("a = "+a+",b = "+b+",c = "+c+",d = "+d);
    }
}

class LinkedDouble{
    int key;
    int val;
    LinkedDouble pre;
    LinkedDouble next;
    LinkedDouble(int key,int val){
        this.key = key;
        this.val = val;
    }
    LinkedDouble(){};
    //移除当前元素，返回值保存当前元素
    LinkedDouble remove(){
        pre.next = next;
        next.pre = pre;
        next = null;
        pre = null;
        return this;
    }

    //插入到当前节点后面
    void insert(LinkedDouble node){
        node.next = next;
        node.pre = this;
        next.pre = node;
        next = node;
    }
}